{% if let Some(docstring) = docstring -%}
{{ crate::utils::prefix_lines(docstring, "/// ") }}
{%- endif %}
type {{ name }} struct {
    {% for field in fields -%}
    {{ field.render()? }}
    {%- endfor %}
    {% if dynamic -%}
    DynamicProperties map[string]any
    {%- endif %}
}

func (c *{{ name }}) Decode(holder *cffi.CFFIValueClass, typeMap baml.TypeMap) {
	typeName := holder.Name
	if typeName.Namespace != {{ pkg.namespace() }} {
		panic(fmt.Sprintf("expected {{ pkg.namespace() }}, got %s", string(typeName.Namespace.String())))
	}
	if typeName.Name != "{{ name }}" {
		panic(fmt.Sprintf("expected {{ name }}, got %s", typeName.Name))
	}

   {% if dynamic %}
   c.DynamicProperties = make(map[string]any)
   {% endif %}

	{% if fields.len() > 0 %}
	for _, field := range holder.Fields {
		key := field.Key
		valueHolder := field.Value
			switch key {
				{% for field in fields %}
				case "{{ field.name }}":
					c.{{ field.name|exported_name }} = {{ field.type.decode_from_any("valueHolder", pkg) }}
				{% endfor %}
		default:
			{% if dynamic %}
			c.DynamicProperties[key] = baml.Decode(valueHolder)
			{% else %}
			panic(fmt.Sprintf("unexpected field: %s in class {{ name }}", key))
			{% endif %}
		}
	}
{% endif %}
}

func (c {{ name }}) Encode() (*cffi.CFFIValueHolder, error) {
    fields := map[string]any{}
    {% for field in fields %}
    fields["{{ field.name }}"] = c.{{ field.name|exported_name }}
    {% endfor %}
    return baml.EncodeClass(c.BamlEncodeName, fields, {% if dynamic %}&c.DynamicProperties{% else %}nil{% endif %})
}

func (c {{ name }}) BamlTypeName() string {
    return "{{ name }}"
}

func (u {{ name }}) BamlEncodeName() *cffi.CFFITypeName {
    return &cffi.CFFITypeName{
        Namespace: {{ pkg.namespace() }},
        Name:      "{{ name }}",
    }
}